import ttkbootstrap as ttk
from ttkbootstrap.scrolled import ScrolledFrame
from ttkbootstrap.constants import *
from ttkbootstrap.dialogs.dialogs import Messagebox
from tkinter.filedialog import askopenfilename
import get
import save
import read
import parse
import config

class SpiderEngine(ttk.Frame):

    def __init__(self, master):
        super().__init__(master, padding=15)
        self.pack(fill=BOTH, expand=YES)

        # 程序变量
        self.master = master
        self.spider_url_var = ttk.StringVar(value=base_url)
        self.save_type_var = ttk.StringVar(value='html')
        self.results = []

        # 配置容器
        option_text = "爬取网页配置"
        self.option_lf = ttk.Labelframe(self, text=option_text, padding=15)
        self.option_lf.pack(fill=X, expand=False, anchor=N)

        self.create_url_row()
        self.create_type_row()
        self.create_btn_row()
        self.create_results_frame()


    def create_url_row(self):
        """添加爬取网址到 LabelFrame """
        url_row = ttk.Frame(self.option_lf)
        url_row.pack(fill=X, expand=YES, pady=(0, 20))
        url_lbl = ttk.Label(url_row, text="爬取网页", width=8)
        url_lbl.pack(side=LEFT, padx=(15, 0))
        url_ent = ttk.Entry(url_row, textvariable=self.spider_url_var)
        url_ent.pack(side=LEFT, fill=X, expand=YES, padx=5)
        spider_btn = ttk.Button(
            master=url_row, 
            text="爬取", 
            command=self.on_spider_url, 
            width=8
        )
        spider_btn.pack(side=LEFT, padx=5)


    def create_type_row(self):
        """添加爬取下来的网页保存内容的类型到 LabelFrame"""
        type_row = ttk.Frame(self.option_lf)
        type_row.pack(fill=X, expand=YES, anchor=N)
        type_lbl = ttk.Label(type_row, text="保存类型", width=8)
        type_lbl.pack(side=LEFT, padx=(15, 0))

        txt_opt = ttk.Radiobutton(
            master=type_row, 
            text="文本", 
            variable=self.save_type_var, 
            value="txt"
        )
        txt_opt.pack(side=LEFT)

        html_opt = ttk.Radiobutton(
            master=type_row, 
            text="网页", 
            variable=self.save_type_var, 
            value="html"
        )
        html_opt.pack(side=LEFT, padx=15)


    def create_btn_row(self):
        """ 两个按钮: 增加和删除,用于网页上元素查找 """
        btn_row = ttk.Frame(self)
        btn_row.pack(fill=X, pady=10)

        insert_btn = ttk.Button(
            master=btn_row, 
            text="添加", 
            width=8, 
            command=self.on_insert_element, 
            bootstyle=(SUCCESS, OUTLINE)
        )
        # insert_btn.place(x=0,y=150)
        insert_btn.pack(side=LEFT)

        delete_btn = ttk.Button(
            master=btn_row, 
            text="删除", 
            command=self.on_delete_element, 
            width=8,
            bootstyle=(DANGER, OUTLINE)
        )
        # delete_btn.place(x=120,y=150)
        delete_btn.pack(side=LEFT,padx=(10, 0))

        # 导入本地html文件
        import_btn = ttk.Button(
            master=btn_row, 
            text="导入本地网页", 
            command=self.on_import_file, 
            width=10,
            bootstyle=SUCCESS
        )
        import_btn.pack(side=LEFT,padx=(10,0))


    def create_results_frame(self):
        """ 将要查询的元素统一放在此处 """
        self.resultFrame = ScrolledFrame(
            master=self,
            autohide=True,
            height=300,
            padding=15
        )
        self.resultFrame.pack(fill=X,pady=10) 


    def on_spider_url(self):
        """爬取网页"""
        print("爬取网页:", self.spider_url_var.get(),",类型:", self.save_type_var.get())
        self.popup_messagebox("正在爬取网页!")      
        spider_text = get.html(self.spider_url_var.get())
        url_title = parse.getUrlTitle(spider_text)
        if url_title is not None or self.save_type_var.get() != "html":
            self.filepath = save.html(spider_text, url_title) 
        else:
            self.filepath = save.file(spider_text) 
        
        self.popup_messagebox("爬取成功!保存地址:" + self.filepath)
        print("爬取成功!保存地址:" + self.filepath)


    def on_insert_element(self):
        """ 添加查询元素 """
        self.insert_result_row()


    def on_delete_element(self):
        """ 从查询元素中删除 """
        for item in self.results[:]:
            if item["check"].get() == 1:
                # 选中的元素进行删除
                print("删除元素:", item["element"])
                item["element"].destroy()
                self.results.remove(item)


    def insert_result_row(self):
        """ 向滚动区域添加一条查询元素(xpath) """

        result_item_row = ttk.Frame(self.resultFrame)
        result_item_row.pack(fill=X, pady=5)

        # 添加进results数组,以待销毁
        self.results.append({"element":result_item_row})
        self.results[-1]["check"] = ttk.IntVar()

        checkbox = ttk.Checkbutton(result_item_row, variable=self.results[-1]["check"])
        checkbox.pack(side=LEFT,ipady=3)

        item_ent = ttk.Entry(result_item_row)
        item_ent.pack(side=LEFT, fill=X, expand=YES, padx=5, ipady=3)

        self.results[-1]["entry"] = item_ent
        current_element = self.results[-1]["entry"]

        continue_btn = ttk.Button(
            master=result_item_row, 
            text="继续", 
            width=8,  
            command=lambda: self.on_continue_element(current_element),
            bootstyle=WARNING
        )
        continue_btn.pack(side=LEFT, padx=5, ipady=3)


    def popup_messagebox(self, title):
        self.toplevel = ttk.Toplevel(alpha=0.0)
        self.toplevel.position_center()
        Messagebox.ok(title,title="消息",parent=self.toplevel, command=self.on_messagebox)


    def on_messagebox(self):
        # 销毁顶级窗口
        self.toplevel.destroy()

    
    def on_import_file(self):
        """ 导入本地网页文件 """
        open_file_path = askopenfilename(
            filetypes =[('网页文件', '*.html'),('文本文件', '*.txt')], 
            initialdir="./", 
            title="选择网页文件"
        )
        if open_file_path == "":
            self.popup_messagebox("没有选择任何文件")
        else:
            # 保存到程序中
            self.filepath = open_file_path


    def on_continue_element(self, element_xpath):
        """ 点击继续,获取xpath路径的文本、链接 """
        if hasattr(self,'filepath') == False:
            self.popup_messagebox("还没有爬取任何网页或没有导入文件！")
        else:
            print("读取 xpath 路径...", element_xpath.get())
            file_content = read.file(self.filepath)
            parse_etree = parse.Parse(file_content)
            # 获取当前按钮选择的xpath路径
            current_element_xpath = element_xpath.get()
            elements = parse_etree.getElements(current_element_xpath)
            self.change_page(elements)


    def change_page(self, elements):
        """ 改变页面: 返回到爬虫程序 """
        # 隐藏自身容器
        global spider_frame
        spider_frame = self
        spider_frame.pack_forget()
        # 显示爬虫程序页面
        cspider.ContinueSpider(self.master, elements)